/*
** Copyright (c) 2008 Mobile GCalendarManager
**
** Permission is hereby granted, free of charge, to any person
** obtaining a copy of this software and associated documentation
** files (the "Software"), to deal in the Software without
** restriction, including without limitation the rights to use,
** copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the
** Software is furnished to do so, subject to the following
** conditions:
**
** The above copyright notice and this permission notice shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
** OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
** HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
** OTHER DEALINGS IN THE SOFTWARE.
*/

/**
 *
 */
package au.edu.mq.comp.itec800.mgc.lib.calendar;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.List;

import org.apache.log4j.Logger;

import au.edu.mq.comp.itec800.mgc.lib.GCalendarManager;
import au.edu.mq.comp.itec800.mgc.lib.IManager;
import au.edu.mq.comp.itec800.mgc.lib.calendar.event.GCommentManager;
import au.edu.mq.comp.itec800.mgc.lib.calendar.event.GGuestManager;
import au.edu.mq.comp.itec800.mgc.lib.calendar.event.GNotificationManager;
import au.edu.mq.comp.itec800.mgc.util.MGCUtils;
import au.edu.mq.comp.itec800.mgc.util.StringUtils;

import com.google.gdata.client.calendar.CalendarQuery;
import com.google.gdata.client.calendar.CalendarService;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.calendar.CalendarEntry;
import com.google.gdata.data.calendar.CalendarEventEntry;
import com.google.gdata.data.calendar.CalendarEventFeed;
import com.google.gdata.data.extensions.BaseEventEntry;
import com.google.gdata.util.ServiceException;

/**
 * @author Laurent Malvert [laurent.malvert@students.mq.edu.au]
 *
 */
public class GEventManager implements IManager<GEvent>
{
  private static final Logger       logger      = Logger.getLogger(GEventManager.class);

  private GCalendarManager          gcm         = null;
  private CalendarEntry             cal         = null;
  private URL                       calEditUrl  = null;
  private List<GEvent>              evts        = null;

  private GEvent                    curEvt      = null;
  private GGuestManager             guestMgr    = null;
  private GCommentManager           commMgr     = null;
  private GNotificationManager      notifMgr    = null;

  public GEventManager(final GCalendarManager gcm, final CalendarEntry cal)
  {
    if ((gcm == null) || (cal == null))
    {
      throw new InvalidParameterException("parameters cannot be null values.");
    }
    this.gcm        = gcm;
    this.cal        = cal;
    logger.debug("  - instantiated GEventManager for GAccount [" + gcm.getAccount().getUser() + "]");
  }

  public URL                                getEditUrl()
    throws MalformedURLException
  {
    //TODO look if there is a method to get the href without referring directly to the link name
    //maybe the getEditLink() method?    if (calEditUrl == null)
    calEditUrl  = new URL(cal.getLink("alternate", null).getHref());
    return (calEditUrl);
  }

  public GEvent                             create(final GEvent evt)
    throws IOException, ServiceException
  {
    return (create(evt.getBaseEvent()));
  }

  public GEvent                             create(final CalendarEventEntry evt)
    throws IOException, ServiceException
  {
    return (create((BaseEventEntry<CalendarEventEntry>) evt));
  }

  public GEvent                             create(final BaseEventEntry<CalendarEventEntry> evt)
    throws IOException, ServiceException
  {
    return (new GEvent(getCalendarService().insert(getEditUrl(), evt)));
  }


  public GEvent                             create(final String title,
                                                   final String ... properties)
    throws IOException, ServiceException
  {
    final GEvent                            evt = new GEvent();

    if (title != null)
    {
      evt.updateName(title);
    }
    if (StringUtils.isValid(0, properties))
    {
      evt.updateDescription(properties[0]);
    }
    if (StringUtils.isValid(1, properties))
    {
      evt.updateLocation(properties[1]);
    }
    evt.updateTime((StringUtils.isValid(2, properties) ? properties[2] : null),
                   (StringUtils.isValid(3, properties) ? properties[3] : null));
    return (create(evt));
  }

  public static boolean                     delete(final GEvent evt)
    throws IOException, ServiceException
  {
    return (delete(evt.getEvent()));
  }

  public static boolean                     delete(final BaseEventEntry<CalendarEventEntry> evt)
    throws IOException, ServiceException
  {
    boolean                                 status  = false;

    if (evt != null)
    {
      try
      {
        MGCUtils.getGAccount().getService().delete(new URL(evt.getEditLink().getHref()));
        status  = true;
      }
      catch (Exception e)
      {
        /* do nothing */
      }
    }
    return (status);
  }

  public void                               update()
    throws IOException, ServiceException
  {
    CalendarEventFeed                       calEvtFeed;
    List<CalendarEventEntry>                evts;
    final CalendarQuery                     myQuery     = new CalendarQuery(getEditUrl());

    myQuery.setStringCustomParameter("orderby", "starttime");
    myQuery.setStringCustomParameter("singleevents", "true");
    myQuery.setStringCustomParameter("sortorder", "ascending");

    calEvtFeed  = getCalendarService().query(myQuery, CalendarEventFeed.class);
    evts        = calEvtFeed.getEntries();

    this.evts = new ArrayList<GEvent>();
    for (final CalendarEventEntry evt : evts)
    {
      this.evts.add(new GEvent(evt));
    }
  }

  public GEvent                             quickAdd(final String qa)
    throws IOException, ServiceException
  {
    final GEvent                            evt   = new GEvent();

    evt.getEvent().setQuickAdd(true);
    evt.getEvent().setContent(new PlainTextConstruct(qa));
    return (create(evt));
  }

  public static void main(final String[] args)
  {
    try
    {
      new GEventManager(null, null).quickAdd("test");
    }
    catch (IOException e)
    {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    catch (ServiceException e)
    {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }


  public GEvent                             get(final String evtId)
    throws IOException, ServiceException
  {
    int                                     idx   = -1;
    List<GEvent>                            evts  = getAll();
    GEvent                                  evt   = null;

    try
    {
      idx   = Integer.parseInt(StringUtils.clean(evtId));
      evt   = evts.get(idx);
    }
    catch (final NumberFormatException ex)
    {
      for (final GEvent e : evts)
      {
        if (e.getName().equalsIgnoreCase(evtId))
        {
          evt = e;
          break;
        }
      }
    }
    catch (IndexOutOfBoundsException e)
    {
      //well wrong idx, do nothing. (We should print an error msg to the user)
    }
    return (evt);
  }

  public List<GEvent>                       getAll()
    throws IOException, ServiceException
  {
    if (evts == null)
      update();
    return (evts);
  }

  public GCalendarManager                   getCalendarManager()
  {
    return (gcm);
  }

  public CalendarEntry                      getCalendar()
  {
    return (cal);
  }

  public CalendarService                    getCalendarService()
  {
    return (getCalendarManager().getAccount().getService());
  }

  public GNotificationManager               getNotificationManager()
  {
    return (notifMgr);
  }

  public GGuestManager                      getGuestManager()
  {
    return (guestMgr);
  }

  public GCommentManager                    getCommentManager()
  {
    return (commMgr);
  }

  public void                               setCurrentEvent(final GEvent evt)
  {
    curEvt  = evt;
    if (curEvt != null)
    {
      guestMgr  = new GGuestManager(this, curEvt);
      commMgr   = new GCommentManager(this, curEvt);
      notifMgr  = new GNotificationManager(this, curEvt);
    }
    else
    {
      guestMgr  = null;
      commMgr   = null;
      notifMgr  = null;
    }
  }

  public GEvent                             getCurrentEvent()
  {
    return (curEvt);
  }
}
